home *** CD-ROM | disk | FTP | other *** search
- TPPDMENU.PAS 11:38:21 PM Jan 11, 1990
-
- Pull down menus for Turbo Pascal Applications
-
- Copyright August 1989, January 1990 -- Ken Henderson
-
- Lots of libraries and routines have been developed in order to
- give the pascal programmer the sleekness of pull down menus in
- his applications. This is no exception. This one differs in
- that no code is generated, the menus are file based and as such
- are very flexible. You can keep the menu data in binary .MNU
- files, you can build it into your applications -- whatever you
- want. The actual invocation of the menus only requires one line
- of code and is the same regardless of the contents of the menus.
- Based in part on the editor toolbox menus and requiring the Turbo
- Professional library of routines from TurboPower Software, these
- menus offer unmatched flexibility and speed. The process, simply
- put, is: you create a menu data file, compile it with the
- supplied menu compiler, and reference it from within your
- application -- that's all there is to it -- and there you have it
- -- pull down menus that are both flexible and incredibly fast.
-
- The question arises: "If I have Turbo Professional, why would I
- need your pull down menus unit? TPMENU suits me just fine."
- Well, you indeed might not need this unit if you have Turbo
- Professional and TPMENU. I use this unit because a) I can change
- the menus without recompiling the code that uses them b) I like
- to distribute the menu source and compiler with my applications
- so that my users can modify the menus if they like (to change the
- trigger keys, etc.) and c) because these menus only require two
- calls to initialize and invoke the menus. I love the Turbo
- Professional stuff and you might not need this unit. If you
- think you might, read on.
-
- The first step in using TPPDMENU is to build the menu data file
- on which the menus are based. This is simple and will be covered
- later. The second step is to call the initialization routine
- from within your program. It has the form:
-
- Function InitMenus(MenuName : String; ColorTable : MenuAttributeArray;
- UserDefinedHelpPtr,
- UserDefinedValidationPtr,
- UserDefinedEvaluatePtr,
- UserDefinedExitMenusPtr,
- BuiltInMenuAddress : Pointer) : Integer;
-
- Menuname is the name of the file containing the menu data, pass
- an empty string if you are using built-in data (covered below).
- Calling InitMenus with the name of a menu file would go something
- like this:
-
- InitMenus('MYMENUS.MNU',MenuColors,nil,nil,nil,nil,nil);
-
- ColorTable is the table of colors to be used by TPPDMENU when
- displaying the menus. You will probably want to have two such
- tables, one for color and the other for mono, and send one of
- them to TPPDMENU based on the current display mode. The
- ColorTable is of type MenuAttributeArray and has the following
- form:
-
- TextColor, {Normal menu color}
- FrameColor, {Menu frame color}
- SelectColor, {Selected menu item color}
- HighLightColor {Highlighted selection character in menu}
-
- MenuAttributeArray = array[ColorType] of Byte;
-
- UserDefindedHelpPtr is used to pass the address of a routine to
- be invoked when F1 is pressed. If you aren't using this feature
- pass nil in its place. It is a generic pointer type which is
- "absoluted" to a global variable of UserHelpType and should be of
- the form:
-
- {$F+}
- Procedure(OptionIndex : Integer);
- {$F-}
-
- UserDefinedValidationPtr is used to pass the address of a routine
- to validate a user's access to a particular menu option. Using
- this routine, you can allow access to some routines, while not
- allowing others. For instance, you might not want to give the
- user access to the Edit option until he has selected the Open
- option. Routines that are accessible will have their trigger
- keys (usually the first key) highlighted and will allow the user
- to move the selection bar to them. Routines that are not
- accessible will not have their trigger key highlighted, nor will
- the user be able to move the selection key to them. If you are
- not using this option pass a nil value to it. It is a generic
- pointer type which is "absoluted" to a global variable of
- UserValidationType and should be of the form:
-
- {$F+}
- Function(OptionIndex : Integer) : boolean;
- {$F-}
-
- UserDefinedEvaluatePtr is used to evaluate a given menu item's
- status. You may have an option that is, say, a toggle. Its
- status is associated with a particular boolean variable. You
- could use this routine to either display ON or OFF beside the
- text of the menu item in order to show its status. If you are
- not using this option, pass a nil in its place. It is a generic
- pointer type which is "absoluted" to a global variable of
- UserEvaluateType and should be of the form:
-
- {$F+}
- Procedure(C : Integer; Stat : Byte; var S : String);
- {$F-}
-
- UserDefinedExitMenusPtr is used to determine which options
- selected actually cause the menu system to be exited and which
- ones keep the menu system on the screen. Often the only option
- which should have the menus exited is the Quit or Exit option
- itself, depending on your application. If you are building an
- editor, and you have an option that turns block marking on such
- that moving the cursor marks the block, of course you would exit,
- so the user could move the cursor in your editor. If you do not
- intend to use this option, pass a nil value in its place. It is
- a generic pointer type which is "absoluted" to a global variable
- of UserValidationType and should be of the form:
-
- {$F+}
- Function(OptionIndex : Integer) : boolean;
- {$F-}
-
- BuiltInMenuAddress is used to point to the area of memory where
- the menu data is located. This option is exclusive of the
- Menuname option. If you pass the Menuname option, you may not
- pass this one (it will have no effect) and if you pass this
- option you should pass an empty string for the Menuname.
- Essentially, this option's primary use is to bind the menu data
- file into your .EXE. The process is as follows: first create and
- compile the menu data file as you would normally. You may want
- to test the menu data file's contents while it is file-based and,
- once it is satisfactory, bind it to your .EXE. Secondly, use
- Borland's BINOBJ utility to create an .OBJ that can be linked
- into your code using the $L directive. The command line for
- BINOBJ would be something like:
-
- BINOBJ MDATA.MNU MDATA MYMENUS
-
- MDATA.MNU is the name of the binary file to convert, MDATA is the
- name of the .OBJ to create and MYMENUS is the name of the dummy
- identifier that you may reference by address for TPPDMENU's
- purposes. You could then call InitMenus with the following
- parms:
- InitMenus('',MenuColors,nil,nil,nil,nil,@MYMENUS);
-
- The PUBLIC identifier, MYMENUS, created by BINOBJ, just gives us
- something with which to reference the area of memory containing
- the menu data.
-
- A conditional define, called AllowHotKeys, allows you to have
- keys which begin with a null (most special keys, such as the
- function keys, and the Alt and Ctrl key combinations) to
- essentially exit from the menu system to be processed by your
- application. For instance, you could set up Alt-X to exit the
- application. When Alt-X was pressed (with AllowHotKeys defined)
- the menus would exit and would insert the key sequence for Alt-X
- into the keyboard buffer. Your application could then read the
- keyboard and determine that the user wanted to exit and then do
- so.
-
- Be sure to declare any of the procedure or function addresses you pass to
- TPPDMENU as far using the $F+ compiler directive.
-
- Here is a simple program which uses TPPDMENU:
-
- {===============================================================}
-
- {
- TESTMENU.PAS
- }
-
- program Test;
- {-Test pulldown menus}
-
- uses
- TpCrt, {screen routines - standard unit}
- Dos, {dos calls - standard unit}
- TpString, {string handling}
- TpPdmenu; {pulldown menu interface}
-
- var
- choice : integer;
- exitm : boolean;
- Ch : char;
- Attribs : MenuAttributeArray; {Currently selected attributes}
-
- const
- MonoAttr : MenuAttributeArray = {For mono systems}
- (
- $07, {TextColor}
- $0F, {FrameColor}
- $70, {SelectColor}
- $0F {HighLightColor}
- );
-
- ColorAttr : MenuAttributeArray = {For color systems}
- (
- $70, {TextColor}
- $78, {FrameColor}
- $0F, {SelectColor}
- $74 {HighLightColor}
- );
-
- begin {Test menus}
-
- {-Initialize some variables}
- choice := 0;
- exitm := false; {-Is passed thru GetMenuChoice; must be set to True if
- Hot keys are to be processed properly}
-
- {-Set up color table}
- case CurrentMode of
- 2, 7 :
- Attribs:=MonoAttr;
- else
- Attribs:=ColorAttr;
- end;
-
- {-Initialize menu system with color set Attribs, no user help, no user
- validation, no user special variable evaluation and no exit check}
-
- if InitMenus('TEST.MNU',Attribs,nil,nil,nil,nil,nil) = 0 then
- GetMenuChoice(choice,exitm);
-
- {-Show the choice}
-
- clrscr;
- Writeln(choice);
- ch:=readkey;
- end. {Test menus}
-
- {===============================================================}
-
- Note that InitMenus returns a numeric value; if the value is
- non-zero an error of some sort has occured. The posible return
- values are:
-
- Value Meaning
- -1 Insufficient memory
- -2 Root menu is not first in the menu data
- -3 Too many submenus have been specified
- -4 Level number is out of synch in menu data
- -5 Error opening the menu data file
- -6 Error reading the menu data file
-
- Below is a sample menu data file. It appears a little confusing
- at first, but is actually very simple.
-
- {===============================================================}
-
- *
- * TEST.MSC
- * MENU SOURCE FILE
- * COMPILE WITH MAKEPMNU
- *
- *
- *
- *
-
- ************************ Main menu
- *menulev, xposn, yposn, xsize, ysize, submax
- 1, 5, 4, 40, 1, 2
- ************************ Main menu selections
- *command, dispoffset, special, selectoffset, string
- 255, 2, 0, 0, 'Install'
- 255, 11, 0, 0, 'Quit'
- ************************ Install menu
- 2, 6, 6, 23, 4, 4
- 255, 0, 0, 0, 'Keyboard'
- 1, 1, 0, 0, 'Switches'
- 2, 2, 0, 0, 'Colors'
- 255, 3, 0, 0, 'Macros...'
- ************************ Keyboard menu
- 3, 19, 8, 20, 2, 2
- 3, 0, 3, 0, 'Read'
- 4, 1, 0, 0, 'Edit'
- ************************ Switches menu (none, required as placeholder)
- 3, 1, 8, 10, 0, 0
- ************************ Colors menu (none, required as placeholder)
- 3, 1, 8, 10, 0, 0
- ************************ Macros menu
- 3, 19, 10, 20, 3, 3
- 5, 0, 3, 0, 'Read'
- 6, 1, 0, 0, 'Edit'
- 7, 2, 0, 0, 'Delete'
- ************************ Quit "menu"
- 2, 13, 6, 10, 1, 1
- 50, 0, 0, 0, 'Quit'
- 255
-
-
- menulevel ─────┐
- │ xposition │
- │ │ yposition │
- │ │ │ menuwidth ├─Header
- │ │ │ │ menudepth │
- │ │ │ │ │ maximum items │
- │ │ │ │ │ │ │
- 2, 6, 6, 23, 4, 4 ─────┘
-
- 255, 0, 0, 0, 'Keyboard' ─────┐
- 1, 1, 0, 0, 'Switches' │
- 2, 2, 0, 0, 'Colors' │
- 255, 3, 0, 0, 'Macros...' │
- │ │ │ │ │ │
- │ │ │ │ itemtext ├─Body
- │ │ │ │ │
- │ │ │ trigger offset │
- │ │ variabletype │
- │ itemnumber │
- │ │
- commandorder ─────┘
-
- Menu level : the level of the current menu. Levels start at 0 and can be
- as high as 3. Each submenu is one level greater than its parent menu level.
-
- HEADER:
- Xposition : the horizontal position of this menu
-
- Yposition : the vertical position of this menu
-
- Menuwidth : the horizontal width of this menu
-
- Menudepth : the vertical depth of this menu
-
- Maxitems : the number of items on this menu
-
- BODY:
- Commandorder : the command number of the associate command or function.
-
- Itemnumber : this menu option's order among the other menu options.
-
- Variabletype : the type of the variable you wish to display next to this
- option -- 0 for none, 1 for boolean (logical), 2 for
- numeric and 3 for string. TPPDMENU passes this value to
- your evaluator routine so that you may display a variables
- value along side it on the menus. Leave the value set to
- 0 if you do not intend to display a value beside this menu
- option.
-
- Triggeroffset : is the offset, less one, where the trigger is located in
- the Itemtext. In other words, if this option is set to
- 0, the trigger key is the first letter of the Itemtext
- and so on
-
- Itemtext : the actual text that composes a menu item. The first
- character of a menu item is normally it's "trigger key" --
- the key that causes it to be executed, no matter where you
- happen to be in its particular menu.
-
-
- Note items which have submenus to them are listed as Commandord 255. Also
- note that the list ends with a lone 255, this is the EOM, or End of Menu
- marker. Since there is no way to tie a particular submenu to a menu option,
- it is done sequentially, that is, the first submenu following a menu is
- associated with menu item 0, the second with menu item 1 and so on.
- Therefore, if you wish to have options on the same menu which reference
- submenus and others which do not, you will have to set up place holder or
- filler menus. These are simply menus associated with a particular menu item
- that does not actually have a submenu associated with it, but precedes one
- that does. A filler menu need only be one line long and does actually contain
- any menu items. The Switches and Colors submenus above are examples of such
- menus. They do not actually represent submenus themselves, but are necessary
- because we wish to place the Keyboard and Macro submenu options on opposite
- ends of their parent menu, Install.
-
-
- {===============================================================}
-
- Compiling with MAKEPMNU
-
- TPPDMENU menu files are compiled with a supplied utility MAKEPMNU. You may
- distribute MAKEPMNU with your applications, if you like, so that your users
- may customize their menus.
-
- Using MAKEPMNU is easy, just pass it the name of the menu file to compile.
- The menu source file extension defaults to .MSC and the menu object file
- extension defaults to .MNU. Even with the biggest menu source
- files, the compile should complete in a second or two.
-
- MAKEPMNU test
-
- {===============================================================}
-
- Here are a few routines to serve as examples of those you might
- pass to InitMenus:
-
- {Here is one to be passed as an evaluator -- a routine to display
- text along side a menu option}
- {$F+}
- procedure EvaluateMenuOpt(C : Integer; Stat : Byte; var S : String);
- var
- Ss : string;
- begin
- Ss := '';
- case stat of {-status of three indicates a string}
- 3 : begin
- case C of
- 3 : Ss := JustFileName(kbdin); {-Display the name of the keyboard
- file that was read}
- 5 : Ss := JustFileName(MacroInFile); {-Display the name of the macro
- file that was read}
- end;
- end;
- end;
- Move(Ss[1], S[Length(S)-Length(Ss)], Length(Ss));
- end;
-
- {Here is one to serve as a menu exit function -- it determines
- whether the menus should be erased when a choice is made, or
- whether they should be left active}
-
- Function AllowExit(C : Integer): Boolean;
- begin
- AllowExit := false;
- If C=50 then AllowExit:=True; {Only the Quit option exits the menus}
- end;
-
- {This routine determines whether a specific item is accesible
- based on whether a variable has been initialized with a value yet}
-
- Function AllowAccess(AccessIndex : Integer) : boolean;
- begin
- AllowAccess:=True;
- case AccessIndex of
- 6,7 : if MacroInFile = '' then AllowAccess:=false;
- {-Don't allow Editing or Deleting of macros unless some have been
- loaded}
- end;
- end;
-
- {===============================================================}
-
- ToggleBooleanVal(var InBoolean : boolean);
-
- ToggleBooleanVal allows you to force a toggle option to either ON
- or OFF. When Space or BackSpace is pressed while in the menus
- the global variable, ToggleBoolean, will be set to either 1,
- when Backspace is pressed, to force it to OFF, or 2, when Space
- is pressed, to force it to ON. The menus will then behave as
- though Enter were pressed and your application should use
- ToggleBooleanVal to toggle the boolean variable appropriately.
- This would allow you to force a toggle to a particular value
- without knowing its prior state, a feature handy in keyboard
- macros. You can use ToggleBooleanVal to toggle the value whether
- Space or Backspace or just the Enter key was pressed. If Space
- or Backspace where not pressed (and, consequently
- ToggleBoolean=0) the routine will simply toggle the value passed
- to it.
-
- {===============================================================}
-
- >>>>>FEATURES NEW TO THIS RELEASE OF TPPDMENU
-
- I have added mouse support with this release of TpPdMenu via the
- TpPdMous unit. This unit requires TpMouse from TurboPower Software
- and would actually add mouse support to any program, since it simply
- translates mouse movements or pressed buttons into keys and pokes
- them into the keyboard buffer via TpCrt.StuffKey. Currently, the
- left button is the equivalent of pressing <Enter>, the right button
- is the equivalent of pressing <Esc> and pressing both buttons is the
- equivalent of pressing <F1>. You may set both the speed and the
- default button-to-key translations by modifying TpPdMous.
-
- That's about all there is to TPPDMENU. The source is provided to
- both the unit and the compiler, keep in mind that you will need
- Turbo Professional from TurboPower Software in order to use
- TPPDMENU. You may extract the sample program and sample menu data
- file here if you wish for testing the unit.
-
- This unit is distributed as "freeware" and you are under no
- obligation to me for using it. I only ask that you leave my
- copyright notices in tact and that if you redistribute this
- software (either by electronic or other means) you keep the
- files here together and do not omit any of them.
-
- Happy menuing!
-
- Ken Henderson